package com.tqz.rc.api;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.tqz.rc.common.constant.Constants;
import com.tqz.rc.common.constant.DefaultValueConstant;
import com.tqz.rc.common.util.JacksonUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * <p>实例对象。
 *
 * @author tianqingzhao
 * @since 2021/8/26 14:06
 */
public class Instance {

    /**
     * 实例所在的命名空间
     */
    private String namespaceId = DefaultValueConstant.DEFAULT_NAMESPACE_ID;

    /**
     * 实例的id。
     */
    private String instanceId;

    /**
     * 实例的ip，默认为localhost。
     */
    private String ip;

    /**
     * 实例的端口号
     */
    private int port;

    /**
     * 实例权重
     */
    private double weight = 1.0D;

    /**
     * 实例是否健康，默认为<code>true</code>，也就是某一个实例注册上来之后是健康的。
     */
    private boolean isHealthy = true;

    /**
     * 是否是临时节点，默认为临时节点，该版本下目前也只支持临时节点。
     */
    private boolean ephemeral = true;

    /**
     * 该实例所在的集群的名称。
     */
    private String clusterName = DefaultValueConstant.DEFAULT_CLUSTER_NAME;

    /**
     * 该实例所在的服务名称。
     */
    private String serviceName;

    /**
     * 上次的心跳时间。
     */
    private volatile long lastBeat = System.currentTimeMillis();

    /**
     * 是否标记该实例
     */
    private volatile boolean marked = false;

    /**
     * 元数据。
     */
    private Map<String, String> metadata = new HashMap<>();

    public String getNamespaceId() {
        return namespaceId;
    }

    public void setNamespaceId(String namespaceId) {
        this.namespaceId = namespaceId;
    }

    public String getInstanceId() {
        return instanceId;
    }

    public void setInstanceId(String instanceId) {
        this.instanceId = instanceId;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public boolean isHealthy() {
        return isHealthy;
    }

    public void setHealthy(boolean healthy) {
        isHealthy = healthy;
    }

    public boolean isEphemeral() {
        return ephemeral;
    }

    public void setEphemeral(boolean ephemeral) {
        this.ephemeral = ephemeral;
    }

    public String getClusterName() {
        return clusterName;
    }

    public void setClusterName(String clusterName) {
        this.clusterName = clusterName;
    }

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public long getLastBeat() {
        return lastBeat;
    }

    public void setLastBeat(long lastBeat) {
        this.lastBeat = lastBeat;
    }

    public boolean isMarked() {
        return marked;
    }

    public void setMarked(boolean marked) {
        this.marked = marked;
    }

    public Map<String, String> getMetadata() {
        return metadata;
    }

    public void setMetadata(Map<String, String> metadata) {
        this.metadata = metadata;
    }

    public String toInetAddr() {
        return ip + ":" + port;
    }

    @JsonIgnore
    public String getDatumKey() {
        if (getPort() > 0) {
            return getIp() + ":" + getPort() + ":" + Constants.LOCALHOST_SITE + ":" + getClusterName();
        } else {
            return getIp() + ":" + Constants.LOCALHOST_SITE + ":" + getClusterName();
        }
    }

    public String toIpAddr() {
        return getIp() + ":" + getPort();
    }

    public String toJson() {
        return JacksonUtils.toJson(this);
    }

    public String generateInstanceId() {
        return getIp() + "#" + getPort() + "#" + getClusterName() + "#" + getServiceName();
    }

    public String generateInstanceId(Set<String> currentInstanceIds) {
        String instanceIdGenerator = getInstanceIdGenerator();
        if (Constants.SNOWFLAKE_INSTANCE_ID_GENERATOR.equalsIgnoreCase(instanceIdGenerator)) {
            return generateSnowflakeInstanceId(currentInstanceIds);
        } else {
            return generateInstanceId();
        }
    }

    private String getInstanceIdGenerator() {
        return Constants.INSTANCE_ID_GENERATOR;
    }

    private String generateSnowflakeInstanceId(Set<String> currentInstanceIds) {
        int id = 0;
        while (currentInstanceIds.contains(String.valueOf(id))) {
            id++;
        }
        String idStr = String.valueOf(id);
        currentInstanceIds.add(idStr);
        return idStr;
    }
}
